<template>
  <div class="wrapper">
    <Nav :title="characterItem.name" @click="popShow = true" backHide>
      <template v-slot:right>
        <span style="color: #409eff" @click.stop="clearChat">清除记录</span>
      </template>
    </Nav>

    <!--聊天记录-->
    <div class="chatList" id="scroll">
      <template v-for="item in characterItem.chatList">
        <!--用户-->
        <div class="chatItem right" v-if="item.message.role === 'user'">
          <div class="itemContent">
            <span class="name">你</span>
            <span class="content">{{ item.message.content }}</span>
          </div>
          <div class="img flex_center">你</div>
        </div>

        <!--助理-->
        <div class="chatItem left" v-else>
          <img @click="popShow = true" class="img" :src="characterItem.avatar" alt="" />
          <div class="itemContent">
            <span class="name">{{ characterItem.name }}</span>
            <span class="content">{{ item.message.content }}</span>
          </div>
        </div>
      </template>
    </div>

    <!--输入-->
    <div class="inputArea flex">
      <div class="error flex_center" v-if="isError" @click="send">发送失败，重新发送</div>
      <div class="loading flex_center" v-else-if="loading">正在思考中...</div>
      <template v-else>
        <textarea
          class="input"
          v-model="prompt"
          type="textarea"
          placeholder="有什么帮助吗？"
          :border="true"
          :auto-height="true"
          @confirm="search"
          @focus="focus = true"
          @blur="focus = false"
        />
        <button class="flex_center" @click="search">发送</button>
      </template>
    </div>

    <!--助手列表-->
    <u-popup v-model="popShow" mode="right" border-radius="20">
      <div class="characters">
        <div
          :class="['characterItem', index === characterIndex && 'active']"
          v-for="(item, index) in characters"
        >
          <div class="flex_center" @click="changeCharacter(index)">
            <img class="img" :src="item.avatar" alt="" />
            <span class="name">{{ item.name }}</span>
          </div>
        </div>
      </div>
    </u-popup>
  </div>
</template>

<script lang="ts" setup>
import Nav from "@/components/nav.vue";
import { gptSend } from "@/api/gpt";
import { CHARACTERS } from "./constant";

const prompt = ref("");
const loading = ref(false);
const focus = ref(false);
const isError = ref(false);

const send = () => {
  loading.value = true;
  isError.value = false;

  let chatList = characterItem.value.chatList;

  nextTick(() => {
    prompt.value = "";
    const messages = chatList.map((item: any) => {
      return item.message;
    });

    const params = {
      model: "gpt-3.5-turbo",
      messages: characterItem.value.exoText.concat(messages),
    };

    gptSend(params)
      .then((res: any) => {
        if (res.choices) {
          characterItem.value.chatList = chatList.concat(res.choices);

          uni.setStorageSync(
            "chatList_" + characterItem.value.name,
            JSON.stringify(characterItem.value.chatList)
          );

          nextTick(() => {
            const scroll = document.getElementById("scroll");
            if (scroll) scroll.scrollTop = scroll.scrollHeight;
          });
        } else {
          isError.value = true;
        }
      })
      .catch((err) => {
        console.log(err);
        isError.value = true;
      })
      .finally(() => {
        loading.value = false;
      });
  });
};

const search = () => {
  let chatList: any = characterItem.value.chatList;

  chatList.push({
    index: chatList.length,
    message: {
      content: prompt.value,
      role: "user",
    },
  });

  nextTick(() => {
    const scroll = document.getElementById("scroll");
    if (scroll) scroll.scrollTop = scroll.scrollHeight;
  });

  send();
};

const keydown = () => {
  let key: any = window.event.keyCode;
  if (key == 13 && focus.value) {
    search();
  }
};

// 助手列表
const popShow = ref(false);
const characterIndex = ref(0);
const characters = ref(CHARACTERS);
const characterItem = computed(() => {
  return characters.value[characterIndex.value];
});

const changeCharacter = (index: number) => {
  uni.setStorageSync("characterIndex", JSON.stringify(index));
  characterIndex.value = index;
  popShow.value = false;

  uni.setNavigationBarTitle({ title: characterItem.value.name });

  if (characterItem.value.chatList.length === 0) {
    send();
  }
};

// 清除聊天记录
const clearChat = () => {
  uni.showModal({
    title: "提示",
    content: "是否确认删除该聊天记录？",
    success: (res) => {
      if (res.confirm) {
        localStorage.removeItem("chatList_" + characterItem.value.name);
        characterItem.value.chatList = [];
        send();
      }
    },
  });
};

onMounted(() => {
  // #ifdef H5
  document.addEventListener("keydown", keydown);
  // #endif

  // 塞入缓存
  characterIndex.value = Number(uni.getStorageSync("characterIndex") || 0);

  characters.value.forEach((item: any) => {
    let chatList = uni.getStorageSync("chatList_" + item.name);
    if (chatList) {
      item.chatList = JSON.parse(chatList);
    }
  });

  nextTick(() => {
    changeCharacter(characterIndex.value);
  });
});

onUnmounted(() => {
  // #ifdef H5
  document.removeEventListener("keydown", keydown);
  // #endif
});
</script>

<style lang="scss" scoped>
.wrapper {
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: #e4f3fb; /* fallback for old browsers */
}

.flex {
  display: flex;
}

.flex_center {
  display: flex;
  align-items: center;
  justify-content: center;
}

.chatList {
  flex: 1;
  overflow-y: auto;
  padding: 10px;
  padding-bottom: 20px;
  box-sizing: border-box;
}

.error {
  width: 100%;
  height: 40px;
  font-size: 28rpx;
  color: #f00;
  border: 1px solid #f00;
  border-radius: 10rpx;
}

.loading {
  width: 100%;
  height: 40px;
  font-size: 32rpx;
  color: #999;
}

.inputArea {
  background: #fff;
  padding: 10px;
  .input {
    box-shadow: 0 0 5px #ccc;
    display: flex;
    align-items: center;
    padding: 10rpx;
    min-height: 50rpx;
    line-height: 50rpx;
    font-size: 32rpx;
    flex: 1;
  }
  button {
    width: 160rpx;
    height: 70rpx;
    border: none;
    border-radius: 5rpx;
    margin-left: 10rpx;
    outline: none;
    box-shadow: 0 0 5rpx #ccc;
    cursor: pointer;
    background: #409eff;
    color: #fff;
    font-size: 32rpx;
  }
}

.chatItem {
  display: flex;
  margin-top: 20rpx;
  .img {
    width: 80rpx;
    height: 80rpx;
    border-radius: 50%;
    background: #409eff;
    color: #fff;
    font-size: 32rpx;
  }

  &.left {
    justify-content: flex-start;
    .itemContent {
      align-items: flex-start;
      margin-left: 20rpx;
      .content::before {
        left: -10rpx;
        border-right: 10rpx solid #fff;
      }
    }
  }

  &.right {
    justify-content: flex-end;
    .itemContent {
      align-items: flex-end;
      margin-right: 20rpx;
      .content::before {
        right: -10rpx;
        border-left: 10rpx solid #fff;
      }
    }
  }

  .itemContent {
    display: flex;
    flex-direction: column;

    .content {
      padding: 14rpx;
      background: #fff;
      border-radius: 10rpx;
      margin-top: 16rpx;
      position: relative;
      display: inline-block;
      max-width: calc(100vw - 200rpx);
      word-break: break-all;
      line-height: 1.5;
      box-shadow: 0 4rpx 10rpx #ccc;
      &::before {
        content: "";
        position: absolute;
        top: 16rpx;
        width: 0;
        height: 0;
        border-top: 10rpx solid transparent;
        border-bottom: 10rpx solid transparent;
      }
    }
  }
}

.characters {
  width: 400rpx;
  height: calc(100vh - 44px);
  padding: 20px;
  box-sizing: border-box;
  overflow-y: auto;
  .characterItem {
    display: flex;
    align-items: center;
    border-bottom: 1px solid #ddd;
    height: 120rpx;
    padding: 0 20rpx;
    &.active {
      background: #e4f3fb;
    }
    .img {
      width: 80rpx;
      height: 80rpx;
      border-radius: 50%;
    }
    .name {
      margin-left: 20rpx;
    }
  }
}
</style>
